<template>
     <form class="validate-form">
      <slot></slot>
      <div class="submit-area"  @click.prevent="submitForm">
        <slot name="submit">
          <button type="submit" class="btn btn-primary">登录</button>
        </slot>
      </div>
    </form>
</template>

<script lang='ts'>
import { defineComponent, onUnmounted } from 'vue'
import mitt from 'mitt' // 导入mitt

// 自定义的一个类型，函数类型，返回的是一个boolean值
type ValidateFunc=()=>boolean
// 自定义的一个类型，函数类型，返回的是void
type ResetFunc=()=>void
type Events={
  'form-item-created': ValidateFunc,
  'form-item-reset':ResetFunc
}

// 实例化事件监听器
export const emitter = mitt<Events>()

export default defineComponent({
  name: 'ValidateForm',
  emits: ['form-submit'],
  setup (props, context) {
    let funcArr: ValidateFunc[] = []
    let resetArr:ResetFunc[] = []

    // 将监听得到的验证函数都存到一个数组中
    const callback = (func?: ValidateFunc) => {
      if (func) {
        funcArr.push(func)
      }
    }
    const resetCallBack = (func?: ResetFunc) => {
      if (func) {
        resetArr.push(func)
      }
    }
    // 添加监听
    emitter.on('form-item-created', callback)
    emitter.on('form-item-reset', resetCallBack)

    // 点击提交按钮，循环执行数组 得到最后的验证结果
    const submitForm = () => {
      const result = funcArr.map(func => func()).every(result => result) // 这样子就可以拿到表单中每一项的验证结果值
      // 注意：every和some函数会提前终止代码的执行，如果判断出有一个结果值为true或false了就不再继续执行了
      // 解决方法：换成map方法，得到一个数组后再对数组进行判断
      if (!result) {
        resetArr.map(func => func()).every(result => result)
      }
      context.emit('form-submit', result)
    }
    // 删除监听器
    onUnmounted(() => {
      emitter.off('form-item-created', callback)
      emitter.off('form-item-reset', resetCallBack)
      funcArr = []
      resetArr = []
    })
    return {
      submitForm,
      callback,
      resetCallBack
    }
  }
})
</script>
